﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Laos;
using System.Data.Objects.DataClasses;
using System.Data.Metadata.Edm;

namespace EntityFrameworkContrib.PostSharp4EF
{
    /// <summary>
    /// will implement calls to the reportchanging and changed events, but will
    /// also set the changetracker on the property (needed for complex types)
    /// </summary>
    [Serializable]
    class OnComplexPropertySetChangeTrackSubAspect : OnMethodBoundaryAspect
	{
        private readonly string propertyName;

        public OnComplexPropertySetChangeTrackSubAspect(string propertyName, int AspectPriority)
        {
            this.AspectPriority = AspectPriority;
            this.propertyName = propertyName;
        }

        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            // so, eventargs.instance could be the entitytype Person.. trying to set address
            // or it could be a complex type with a property pointing to another complex type

            // igetchangetracker is implemented by both entitytypes as complextypes
            IGetChangeTracker fatherImplementation = (IGetChangeTracker)eventArgs.Instance;

            // the changetracker of our encapsulating type may be null during object materialization
            if (fatherImplementation.GetChangeTracker() != null)
            {
                // TODO: need to reset changetracker on the current value, which we do not have!!!!
                // so we use reflection. Try to find different approach
                object currentValue =eventArgs.Instance.GetType().GetProperty(propertyName).
                    GetGetMethod().Invoke(eventArgs.Instance, new object[] { });
                if (currentValue != null)
                {
                    // so there is already a value there, cast it and remove the changetracker
                    IComplexType currentComplexType = (IComplexType)currentValue;
                    currentComplexType.SetComplexChangeTracker(propertyName, null);
                }


                // report the change
                fatherImplementation.GetChangeTracker().EntityMemberChanging(this.propertyName);
            }

        }

        public override void OnSuccess(MethodExecutionEventArgs eventArgs)
        {
            // so, eventargs.instance could be the entitytype Person.. trying to set address
            // or it could be a complex type with a property pointing to another complex type

            // igetchangetracker is implemented by both entitytypes as complextypes
            IGetChangeTracker fatherImplementation = (IGetChangeTracker)eventArgs.Instance;

            IComplexType value = eventArgs.GetArguments().FirstOrDefault() as IComplexType;


            // the changetracker may be null during object materialization
            if (fatherImplementation.GetChangeTracker() != null)
            {
                // Raises the changed event.
                fatherImplementation.GetChangeTracker().EntityMemberChanged(this.propertyName);
            }


            // finally set the changetracker of the parent to the newly set complextype
            if (value != null)
            {
                value.SetComplexChangeTracker(propertyName, fatherImplementation.GetChangeTracker());
            }

        }
	}
}
